package com.apimarket.service;


import com.apimarket.annotation.MultiDSTransactionalAnnotation;
import com.apimarket.dao.ApplyMapper;
import com.apimarket.dao.DataSetMapper;
import com.apimarket.entity.*;
import com.apimarket.entity.kong.Route;
import com.apimarket.entity.vo.DataSetAndPacketVo;
import com.apimarket.enums.ExceptionEnum;
import com.apimarket.exception.AMException;
import com.apimarket.util.RedisUtils;
import com.apimarket.util.kong.KongRoute;
import com.apimarket.util.kong.KongService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * @Description:
 * @Author ZXR
 * @Date 2021/7/6 15:57
 * @Version 1.0
 */

@Service
public class DataSetService {
    @Autowired
    private DataSetMapper dataSetMapper;
    @Autowired
    private ApiService apiService;
    @Autowired
    private KongService kongService;
    @Value("${zhoushan.datapacket.download}")
    private String packetDownload;
    @Autowired
    private RouteService routeService;
    @Autowired
    private KongRoute kongRoute;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private ApplyMapper applyMapper;
    @Value("${redis.route.key}")
    private String routeRedisKey;
    @Value("${spring.kong.net}")
    private String kongNet;
    private Logger logger= LoggerFactory.getLogger(DataSetService.class);

    public List<Map<Integer,String>> getTypeList() {
        //先看缓存中有没有

        List<Map<Integer,String>> map=dataSetMapper.getTypeList();
        if(map.size()<1){
            throw new AMException(ExceptionEnum.Type_NOT_FOUND);
        }
        return map;
    }

    public PageInfo<Dataset> getPageObject(Integer type, String name,Integer pageSize,Integer pageCurrent) {
        // 1.参数校验
        if(pageCurrent==null||pageCurrent<1)
            throw new IllegalArgumentException("当前页码有误");
        if(pageSize==null||pageSize<1)
            throw new IllegalArgumentException("当前页显示数目有误");
        String orderBy="date desc";
        //传入查询第几页，以及显示多少条
        PageHelper.startPage(pageCurrent,pageSize,orderBy);
        List<Dataset> list=dataSetMapper.findAll(type,name);
        if(list.size()==0){
            throw new AMException(ExceptionEnum.Dataset_NOT_FOUND);
        }
        //丢给pageInfo处理，拿到总条数，页数，页码等等
        PageInfo<Dataset> pageInfo=new PageInfo<>(list);
        return pageInfo;

    }

    //这里还需要做数据一致性问题
    public void addDataset(Dataset dataset, MultipartFile picFile, MultipartFile exampleFile) throws IOException, URISyntaxException {
        if(picFile.getSize()==0||exampleFile.getSize()==0){
            throw new AMException(ExceptionEnum.File_NOT_UPLOAD);
        }
        //存储文件
        String picUrl = apiService.SaveFile(picFile);
        String exampleUrl = apiService.SaveFile(exampleFile);
        dataset.setPicUrl(picUrl);
        dataset.setExampleUrl(exampleUrl);
        //判断传递的json字符串中有没有''，如果有的话需要把它替换为/"
        dataset.setFieldDescription(apiService.replaceDYH(dataset.getFieldDescription()));
        String id = UUID.randomUUID().toString();
        dataset.setId(id);
        dataset.setDate(new Date());
        //初始数据块的下载次数是0
        dataset.setDownloadNum(0);


        //然后需要创建这个数据块对应的service
        String url=packetDownload;
        kongService.addService(url,"",id);
        //创建service之后，还需要创建一个route，让请求能够路由到这个service
        Route route=new Route();
        //随机生成5位长度的字符串
        String path= RandomStringUtils.randomAlphanumeric(5);
        StringBuilder sb=new StringBuilder(path);
        sb.insert(0,"/");
        List<String> pathList=new ArrayList<>();
        pathList.add(sb.toString());
        route.setPaths(pathList);
        route.setService(new Route.Service(id));
        //往业务数据库中添加路由的path，如果重复会抛异常，需要保证path的全局唯一性
        routeService.addRoutePaths(route);
        Route result=kongRoute.addRouteAndJudege(route);
        //添加route成功后需要把缓存中的route信息给删除
        redisUtils.judgeAndRemove(routeRedisKey);

        //然后需要为这个dataset绑定权限控制的插件
        //生成一个能访问这个dataset的权限组
        //这里需要为新创建的service绑定两个插件（acl,key-auth）,同时需要为他创建一个属于这个service的组
        apiService.bindAclAndKeyAuth(id);

        //插入dataset业务数据库
        dataset.setPath(sb.toString());
        dataSetMapper.addDataset(dataset);
    }


    public void deleteDataSet(String id) {
        //先删除数据块表中的数据
        dataSetMapper.deleteDataSet(id);
        //删除数据块下的所有数据包
        dataSetMapper.deletePacketByDatasetId(id);
        //删除对该数据块的申请
        applyMapper.delteByDatasetId(id);
    }

    public void updateDataset(Dataset dataset, MultipartFile picFile, MultipartFile exampleFile) {
        if(picFile!=null){
            if(picFile.getSize()!=0){
                //存储文件
                String picUrl = apiService.SaveFile(picFile);
                dataset.setPicUrl(picUrl);
            }
        }
        if(exampleFile!=null){
            if(exampleFile.getSize()!=0){
                //存储文件
                String exampleUrl = apiService.SaveFile(exampleFile);
                dataset.setExampleUrl(exampleUrl);
            }
        }
        //判断传递的json字符串中有没有''，如果有的话需要把它替换为/"
        dataset.setFieldDescription(apiService.replaceDYH(dataset.getFieldDescription()));
        dataSetMapper.updateDataset(dataset);
    }


    public void packetAdd(DataPacket packet) {
        String id = UUID.randomUUID().toString();
        String datasetId=packet.getDatasetId();
        //需要拿到这个数据包对应的数据块的path
        String path=dataSetMapper.getDataSetPathById(datasetId);
        //拼接生成前端点击下载链接时的访问地址
        StringBuilder sb=new StringBuilder(kongNet);
        //最终生成的下载链接是http://kong服务器地址:8000/path/datapacketId(现在这个不用了)
        //现在用url来作为数据包的下载，url是数据在服务器中的地址
        sb.append(path).append("/").append(id);
        packet.setDate(new Date());
        packet.setId(id);
        packet.setDownloadUrl(sb.toString());
        dataSetMapper.packetAdd(packet);
    }

    public PageInfo<DataPacket> getPacketPageObject(Integer pageSize, Integer pageCurrent, String name,String datasetId) {
        // 1.参数校验
        if(pageCurrent==null||pageCurrent<1)
            throw new IllegalArgumentException("当前页码有误");
        if(pageSize==null||pageSize<1)
            throw new IllegalArgumentException("当前页显示数目有误");
        if(StringUtils.isEmpty(datasetId))
            throw new AMException(ExceptionEnum.ID_IS_NULL);
        //传入查询第几页，以及显示多少条
        PageHelper.startPage(pageCurrent,pageSize);
        List<DataPacket> list=dataSetMapper.findPacketAll(name,datasetId);
        if(list.size()==0){
            throw new AMException(ExceptionEnum.Datapacket_NOT_FOUND);
        }
        //丢给pageInfo处理，拿到总条数，页数，页码等等
        PageInfo<DataPacket> pageInfo=new PageInfo<>(list);
        return pageInfo;
    }

    public void updateDataPacket(DataPacket packet) {
        if(packet.getId()==null)
            throw new AMException(ExceptionEnum.ID_IS_NULL);
        dataSetMapper.updateDataPacket(packet);
    }

    public void deletPacket(String id) {
        int rows=dataSetMapper.deletePacket(id);
        if(rows==0)
            throw new AMException(ExceptionEnum.Record_NOT_FOUND);
    }

    public DataSetAndPacketVo getDataSetDetailAndChildPackets(String id) {
        DataSetAndPacketVo result=dataSetMapper.getDataSetDetailAndChildPackets(id);
        if(result==null)
            throw new AMException(ExceptionEnum.Record_NOT_FOUND);
        return result;
    }

    public Boolean judegeHaveRightToDownload(String datasetId, String userId) {
        //查找用户对数据块审核通过的申请
        List<Apply> apply=applyMapper.getApplyByDatasetAndUser(datasetId,userId);
        if(apply==null||apply.size()==0){
            //没有找到用户对该数据块审核通过的申请
            return false;
        }else{
            return true;
        }
    }

    public void downloadPacket(String datapacketId, String fileURL, HttpServletRequest request
            , HttpServletResponse response) throws IOException {
        //URL url=new URL(fileURL);
        //HttpURLConnection conn=(HttpURLConnection)url.openConnection();
        //设置超时时间为5秒
        //conn.setConnectTimeout(5*1000);
        //防止屏蔽程序抓取而返回403错误
        //conn.setRequestProperty("User-Agent","Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
        //得到输入流
        //InputStream inputStream=conn.getInputStream();
        //获取自己的数组
        //byte[] getData=readInputStream(inputStream);
        logger.info("文件地址是："+fileURL);
        //这里是下载本地文件的写法
        File file=new File(fileURL);


        InputStream inputStream=new BufferedInputStream(new FileInputStream(fileURL));

        //获得浏览器代理信息
        final String userAgent = request.getHeader("USER-AGENT");
        //判断浏览器代理并分别设置响应给浏览器的编码格式
        //String fileName=fileURL.substring(fileURL.lastIndexOf("/"+1));
        String fileName=file.getName();
        String finalFileName = null;
        if(StringUtils.contains(userAgent, "MSIE")||StringUtils.contains(userAgent,"Trident")){//IE浏览器
            finalFileName = URLEncoder.encode(fileName,"UTF8");
            System.out.println("IE浏览器");
        }else if(StringUtils.contains(userAgent, "Mozilla")){//google,火狐浏览器
            finalFileName = new String(fileName.getBytes(), "ISO8859-1");
        }else{
            finalFileName = URLEncoder.encode(fileName,"UTF8");//其他浏览器
        }
        //设置HTTP响应头
        response.reset();//重置 响应头
        response.setContentType("application/x-download");//告知浏览器下载文件，而不是直接打开，浏览器默认为打开
        response.addHeader("Content-Disposition" ,"attachment;filename=\"" +finalFileName+ "\"");//下载文件的名称
        // 循环取出流中的数据
        byte[] b = new byte[1024];
        int len;
        while ((len = inputStream.read(b)) > 0){
            response.getOutputStream().write(b, 0, len);
        }
        response.getOutputStream().flush();
        response.getOutputStream().close();
        inputStream.close();
    }
    public byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }

    public void addDownloadNum(String datapacketId) {
        dataSetMapper.addDownloadNum(datapacketId);
    }
}
